home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Alles Voor Internet / Tout Pour Internet
/
alles voor internet.iso
/
MacInternet™
/
Telnet
/
NCSA
/
tn3270 2.3d26 source
/
tn3270
/
writesf.c
< prev
next >
Wrap
Text File
|
1991-05-23
|
43KB
|
1,619 lines
/*
* tn3270 for the Macintosh Source Code
* Brown University Computing and Information Services
* Version 2.3d21, January 17, 1991
* Copyright (c) 1988, 1989, 1990, 1991 by Brown University and by
* Peter John DiCamillo.
*
* Permission is granted to any individual or institution to use, copy,
* or redistribute the binary version of this software and its
* documentation provided this notice and the copyright notices are
* retained. Permission is granted to any individual or non-profit
* institution to use, copy, modify, or redistribute the source files
* of this software provided this notice and the copyright notices are
* retained. This software may not be distributed for profit, either
* in original form or in derivative works, nor can the source be
* distributed to other than an individual or a non-profit institution.
* Any individual or group interested in seeing and/or using these
* source files but who are prevented from doing so by the above
* constraints should contact Don Wolfe, Assistant Vice-President for
* Computer Systems at Brown University, (401) 863-7250, for possible
* software licensing of the source developed at Brown.
*
* Brown University and Peter John DiCamillo make no representations
* about the suitability of this software for any purpose.
*
* BROWN UNIVERSITY AND PETER JOHN DICAMILLO GIVE NO WARRANTY, EITHER
* EXPRESS OR IMPLIED, FOR THE PROGRAM AND/OR DOCUMENTATION PROVIDED,
* INCLUDING, WITHOUT LIMITATION, WARRANTY OF MERCHANTABILITY AND
* WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE.
*
*/
/* Code in this file supports WSF functions: Query Reply,
normal 3270 data (calls writetm), file transfer (calls
vmxfer), and 3179 graphics. */
/* Reference manuals for graphics support:
IBM 3179 G Color Graphics Display Station Description,
GA18-2261
Reference Information for Picture Interchange Format,
SC33-0244 (part of IBM 3270 PC/G or PC/GX library)
General 3270 data stream information:
IBM 3270 Information Display System Data Stream
Programmer's Reference, GA23-0059 (revision -3 includes
some 3179 information) */
/* Graphics has been tested using SAS version 5.16 with
device names of IBM3179 (SAS built-in support) and
GDDMPCGX (SAS calling GDDM Release 4). Test plots include
the output from the GTESTIT procedure, the "cowboy hat"
sample, and the BITNET topology maps. */
#define __SEG__ 3270wsf
#include "maclib.h"
#include "termdef.h"
#include "globals.h"
#define IAC 255 /* interpret as command: */
#define EOR 239 /* end of record (transparent mode) */
#define adMax 37 /* Color QuickDraw arithmetic drawing max mode */
#define adMin 39 /* Color QuickDraw arithmetic drawing min mode */
/* MacDraw PicComment codes we use */
#define picDwgBeg 130
#define picDwgEnd 131
#define picGrpBeg 140
#define picGrpEnd 141
/* LaserWriter PicComment codes we use */
#define SetLineWidth 182
extern PaletteHandle myPalette;
extern struct Point sfppoint;
extern short vpixsize, hpixsize;
extern Rect textRect;
/* for file xfer */
extern unsigned char * rbuf; /* read buffer */
extern unsigned char * sbuf; /* send buffer */
extern short rlen; /* read length */
extern short slen; /* send length */
extern RGBColor realblack, realwhite;
extern char newserver; /* server supports new protocol */
extern char pendalign; /* pending bitmap alignment call */
extern char skipnewmode; /* cause writetm to skip call to newmode */
/* Code labelled "temp" is included to allow writing debugging data for
graphics support to a file. Writing to the file is suppressed unless
"cs.dblevel" has been set by the main program. */
/*temp*/
#include "stdio.h"
static struct {
unsigned char wsf_op;
unsigned char wsf_gr;
unsigned char grf_op;
} wsfdbg;
short pleft, cleft; /* byte counts for segment processing */
/* default settings (changed by Set Current Defaults) */
unsigned char dfltcolor = 4; /* default color = green */
unsigned char dfltlw = 1; /* default line width = 1 pixel */
unsigned char dfltlt = 7; /* default line type = solid */
unsigned char dfltmarker = 0xb5; /* default marker = diamond */
unsigned char dfltmix = 2; /* default mix mode */
Pattern dfltpat = {0xff, 0xff, 0xff, 0xff, /* default area pattern */
0xff, 0xff, 0xff, 0xff};
/* current settings which must be global */
unsigned char linew = 1; /* current line width */
unsigned char linet = 7; /* current line type */
short copymode = srcCopy; /* current mode for CopyBits */
/* variables for creating PICT file */
char pictopen = 0; /* true when PICT file is open */
char pict_fName[64] = {0}; /* name of open PICT file */
short pictvref; /* volume reference for open PICT file */
short pictfref; /* file reference for open PICT file */
PicHandle picthandle; /* handle for saved picture */
long pictcount; /* size of picture */
pascal void myStdPutPic(); /* subroutine for writing file */
OSErr picterr; /* error (if any) during writing */
CQDProcs myProcs; /* proc pointers for changing */
Handle theWidth; /* Handle for SetLineWidth */
short xmin, xmax, ymin, ymax; /* variables to define rectangle */
char area_active = 0; /* flag to indicate area is active */
char image_active = 0; /* flag to indicate image data is active */
writesf(cmd, len, init) /* write structured field */
unsigned char * cmd; /* command, starting with WSF op-code */
short len; /* command length */
char init; /* false = data continued from last call */
{
short currlen, curroff, fieldlen;
unsigned char fieldid;
char readflg;
if (!init) return; /* currently, must get all data in one call */
if (len < 1) return;
currlen = len - 1; /* skip over wsf op-code */
curroff = 1;
while (currlen >= 3) {
fieldlen = cmd[curroff+1] + (cmd[curroff] << 8);
if (fieldlen == 0) fieldlen = currlen;
fieldid = cmd[curroff+2];
readflg = 0;
intwsf(fieldid, fieldlen, cmd+curroff, &readflg);
if (readflg) break; /* command was a read of some sort */
curroff += fieldlen;
currlen -= fieldlen;
}
}
intwsf(id, len, data, rdflag) /* interpret one wsf field */
unsigned char id; /* wsf field type code */
short len; /* length of data */
unsigned char * data; /* data, starting with 2-byte length */
char * rdflag; /* return 1 if read which generates response */
{
char sess_ext3270;
if (apiopen) {
sess_ext3270 = (apiopenreq.nowsf == 0);
}
else {
sess_ext3270 = cs.ext3270;
}
/* temp */
wsfdbg.wsf_op = id;
wsfdbg.wsf_gr = wsfdbg.grf_op = 0;
switch(id) {
case 0x01: /* read partition */
if (len < 5) break;
if ((data[4] == 0x02) || (data[4] == 0x03))
if (data[3] == 0xff)
wsfrpq(len, data, newserver && (sess_ext3270 == 0));
(*rdflag) = 1;
break;
case 0x03: /* erase/reset */
if (data[3] & 0x80) {
ewamode = 1; /* establish alternate screen size */
}
else {
ewamode = 0; /* establish default screen size */
}
newmode(ewamode, 0);
clrscn(); /* clear text */
drawpict = 1; /* force graphics clear */
clrpict(); /* clear graphics */
break;
case 0x06: /* load PS set */
/* ignore command to clear PS storage */
if ((len == 7) && (data[3] & 0x40)) break;
/* real PS load not supported */
hexdump(data, len); /*temp*/
break;
case 0x09: /* set reply mode */
/* not supported */
hexdump(data, len); /*temp*/
break;
case 0x0c: /* create partition */
/* not supported */
hexdump(data, len); /*temp*/
break;
case 0x0f: /* graphic something */
writegf(data, len);
break;
case 0x20: /* file transfer */
/* special field type made up for Mac3270 */
if (len < 4) break; /* at least one data byte */
rbuf = data+3;
rlen = len-3;
sbuf = readbuff+6;
vmxfer(); /* process file transfer command */
if (slen == 0) break; /* send response, if generated */
readbuff[0] = 0xd7;
slen += 1;
readbuff[5] = 0x88;
rbsize = slen + 5;
if (tcpflg) {
readbuff[rbsize++] = IAC;
readbuff[rbsize++] = EOR;
}
senddata(0xf6, rbsize-3, readbuff+3, 1);
break;
case 0x40: /* outbound 3270DS */
if (len < 5) return;
if (data[4] == 0x6f) { /* EAU */
funckey(10); /* simulate CLEAR key pressed */
rdaid = 0x60;
break;
}
if ((data[3] == 0) && (data[4] == 0xf5)) {
skipnewmode = 1; /* EW with PID = 0 keeps mode */
}
ldvoff = 0; /* normal 3270 data stream */
writetm(data+4, len-4, 1); /* update 3270 buffers */
skipnewmode = 0; /* reset special flag */
invldscr(); /* display new contents */
endwcc(); /* post-write WCC functions */
break;
default:
hexdump(data, len); /*temp*/
break;
}
}
wsfrpq(len, data, shortrsp) /* Read Partition Query */
short len;
unsigned char * data;
char shortrsp;
{
short i, j, listlen, reqtype, t, typecount, wsflen;
static unsigned char long_wsftypes[] = { /* all WSFR resources */
0x86, 0x87, 0x85, 0x81, 0xa6, 0x88, 0x80, 0x84, 0x96, 0x99,
0xa1, 0xa8, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb6, 0x00};
static unsigned char long_wsflist[] = { /* 0x01 if in default list */
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static unsigned char short_wsftypes[] = { /* all WSFR resources */
0x85, 0x81, 0xa6, 0x80, 0xa1, 0x00};
static unsigned char short_wsflist[] = { /* 0x01 if in default list */
0x01, 0x01, 0x01, 0x01, 0x00};
unsigned char *wsftypes, *wsflist;
if (shortrsp) {
wsftypes = short_wsftypes;
wsflist = short_wsflist;
}
else {
wsftypes = long_wsftypes;
wsflist = long_wsflist;
}
switch (data[4]) {
case 0x02: /* Query */
listlen = 0;
reqtype = 1;
break;
case 0x03: /* Query List */
if (len < 6) return;
listlen = len - 6;
reqtype = (data[5] & 0xc0) >> 6;
if (reqtype == 3) return;
break;
default:
return;
}
typecount = strlen(wsftypes);
wsflen = 0;
for (i=0; i < typecount; i++) { /* loop through all possible responses;
include in response those requested */
t = wsftypes[i]; /* t = resource number */
if (reqtype == 2) { /* all types */
wsfadd(t, &wsflen, shortrsp);
if (t == 179) wsfadd(254, &wsflen, shortrsp); /* 2nd port response */
continue;
}
if ((reqtype == 1) && (wsflist[i] != 0)) { /* default types wanted */
wsfadd(t, &wsflen, shortrsp);
if (t == 179) wsfadd(254, &wsflen, shortrsp); /* 2nd port response */
continue;
}
if (listlen == 0) continue; /* listed types wanted */
for (j=0; j < listlen; j++)
if (data[j+6] == t) {
wsfadd(t, &wsflen, shortrsp);
if (t == 179) wsfadd(254, &wsflen, shortrsp); /* 2nd port response */
break;
}
}
/* return null response if no other */
if (wsflen == 0) wsfadd(255, &wsflen, shortrsp);
readbuff[0] = 0xd7; /* send the response, similarly to read modified */
wsflen += 1;
readbuff[5] = 0x88; /* AID code = 0x88 (structured field) */
rbsize = wsflen + 5;
if (tcpflg) {
readbuff[rbsize++] = IAC;
readbuff[rbsize++] = EOR;
}
senddata(0xf6, rbsize-3, readbuff+3, 1);
}
wsfadd(num, len, shortrsp) /* add resource no. "num" to response */
short num;
short *len;
char shortrsp;
{
unsigned char **rhandle;
short rlen, rnum;
void (*procptr)();
void def_ua();
void def_ip();
unsigned char rscbuff[64];
rnum = num; /* default resource is argument */
switch(num) {
case 129: procptr = def_ua; /* usable area */
break;
case 166: procptr = def_ip; /* implicit partition */
break;
default: procptr = 0;
break;
}
if (ses_altptsize == 12) {
switch(num) {
case 133: rnum = 252; /* character sets */
break;
case 182: rnum = 250; /* graphic symbol sets */
break;
default: break;
}
}
if (colormac) if (num == 134) rnum = 245;
if (shortrsp) if (num == 128) rnum = 244;
if (cs.simps) { /* include PS character set response */
if (rnum == 133) rnum = 251;
if (rnum == 252) rnum = 253;
}
rhandle = (unsigned char **)GetResource('WSFR', rnum);
if (rhandle == 0) return; /* should report error here */
rlen = ((*rhandle)[0] << 8) + (*rhandle)[1];
/* modify response which depends on screen format */
if (procptr != 0) {
movmem((*rhandle), rscbuff, rlen);
(*procptr)(rscbuff, rlen);
tcpmovmem(rscbuff, readbuff+6+(*len), &rlen);
}
else {
tcpmovmem((*rhandle), readbuff+6+(*len), &rlen);
}
(*len) += rlen;
}
/* modify usable area response for screen format */
void def_ua(resptr, reslen)
uareply *resptr;
short reslen;
{
union {
unsigned short i;
unsigned char s[2];
} cvt;
resptr->w = 80;
resptr->h = 24;
switch (ses_dfltptsize) {
case 12:
resptr->aw = 7;
resptr->ah = 16;
break;
default:
resptr->aw = 6;
resptr->ah = 12;
break;
}
cvt.i = ses_altcols;
movmem(cvt.s, resptr->waua, 2);
cvt.i = ses_altrows;
movmem(cvt.s, resptr->haua, 2);
switch (ses_altptsize) {
case 12:
resptr->awaua = 7;
resptr->ahaua = 16;
break;
default:
resptr->awaua = 6;
resptr->ahaua = 12;
break;
}
}
/* modify implicit partition response for screen format */
void def_ip(resptr, reslen)
ipreply *resptr;
short reslen;
{
union {
unsigned short i;
unsigned char s[2];
} cvt;
cvt.i = 80;
movmem(cvt.s, resptr->wd, 2);
cvt.i = 24;
movmem(cvt.s, resptr->hd, 2);
cvt.i = ses_altcols;
movmem(cvt.s, resptr->wa, 2);
cvt.i = ses_altrows;
movmem(cvt.s, resptr->ha, 2);
switch (ses_dfltptsize) {
case 12:
cvt.i = 7;
movmem(cvt.s, resptr->wcd, 2);
cvt.i = 16;
movmem(cvt.s, resptr->hcd, 2);
break;
default:
cvt.i = 6;
movmem(cvt.s, resptr->wcd, 2);
cvt.i = 12;
movmem(cvt.s, resptr->hcd, 2);
break;
}
switch (ses_altptsize) {
case 12:
cvt.i = 7;
movmem(cvt.s, resptr->wca, 2);
cvt.i = 16;
movmem(cvt.s, resptr->hca, 2);
break;
default:
cvt.i = 6;
movmem(cvt.s, resptr->wca, 2);
cvt.i = 12;
movmem(cvt.s, resptr->hca, 2);
break;
}
}
writegf(data, len) /* graphic data stream */
unsigned char * data;
short len;
{
short i;
wsfdbg.wsf_gr = data[3]; /*temp*/
switch(data[3]) {
case 0x0f: /* graphic data */
/* not supported */ /* controls inbound graphics data */
hexdump(data+7, len-7); /*temp*/
break;
case 0x10: /* graphic picture */
if (data[5] & 0x80) {
pleft = 0; /* if first, reset count */
initpict(); /* maybe start of new picture */
}
if (len < 8) break;
for (i=7; i < len; i++) grpparse(data[i]);
if (data[5] & 0x40) showpict(); /* if last, show result */
break;
case 0x11: /* graphic control */
if (data[5] & 0x80) {
cleft = 0; /* if first, reset count */
initpict(); /* maybe start of new picture */
}
if (len < 8) break;
for (i=7; i < len; i++) grcparse(data[i]);
if (data[5] & 0x40) showpict(); /* if last, show result */
break;
case 0x1f: /* OEM data */
/* not supported */
hexdump(data+7, len-7); /*temp*/
break;
default: hexdump(data+7, len-7); /*temp*/
break;
}
}
grpparse(c) /* interpret graphic picture data */
unsigned char c;
{
static short ptemp1, pboff, pcount;
static char pmode;
static unsigned char pictbuff[257];
if (pleft == 0) {
pmode = pcount = 0;
pleft = 14;
}
switch (pmode) {
case 0: /* processing segment header */
if (pcount == 8) ptemp1 = c;
if (pcount == 9) pleft = (ptemp1 << 8) + c + 5;
if (pcount == 13) {
pmode = 1;
pcount = 0;
}
else pcount++;
break;
case 1: /* processing order */
if (pcount == 0) {
pboff = 0;
pictbuff[pboff++] = c;
if ((c==0x00) || (c==0x20) || (c==0xff)) {
exdraw(pictbuff, pboff);
pcount = 0;
}
else pcount++;
break;
}
pictbuff[pboff++] = c;
if (pcount == 1) {
if (((pictbuff[0] <= 0x7f) &&
((pictbuff[0] & 0x0f) >= 8)) || (c == 0)) {
exdraw(pictbuff, pboff);
pcount = 0;
}
else {
ptemp1 = c; /* no. of operand bytes left */
pcount++;
}
break;
}
pcount++;
ptemp1--;
if (ptemp1 == 0) {
exdraw(pictbuff, pboff);
pcount = 0;
}
break;
default:
break;
}
pleft--;
}
exdraw(opdata, len) /* process drawing order */
unsigned char * opdata;
short len;
{
static short xpos, ypos;
short r, s;
union {
short ipos;
char cpos[2];
} cvt;
GrafPtr gp, dp;
short newcolor;
RGBColor rgbtemp;
static unsigned char markchar = 0xb5; /* current marker */
static Pattern fillpat = {0xff, 0xff, 0xff, 0xff, /* current area pattern */
0xff, 0xff, 0xff, 0xff};
static PolyHandle mypoly;
static unsigned char aflags;
static unsigned char markstr[2] = {1, 0}; /* one-byte Pascal string */
static BitMap image_srcBits;
static Rect image_srcRect, image_dstRect;
static short image_rowcount;
unsigned char imagebuff[258];
unsigned char * imageptr;
short imgoffset;
GetPort(&gp);
if (PictPtr != 0) {
SetPort(PictPtr);
setgdev();
}
else {
SetPort(myWindow);
}
GetPort(&dp);
if (cs.dblevel == 3) { /* dump all graphics if level 3 */
wsfdbg.grf_op = opdata[0]; /* temp */
hexdump(opdata, len); /* temp */
}
switch(opdata[0]) {
case 0xa1: /* rel. line at current pos. */
r = opdata[1]/2;
s = 2;
MoveTo(sx(xpos), sy(ypos));
while (r > 0) {
xpos += (char)opdata[s++];
ypos += (char)opdata[s++];
myLineTo(sx(xpos), sy(ypos));
r --;
}
break;
case 0x21: /* set current position */
cvt.cpos[0] = opdata[2];
cvt.cpos[1] = opdata[3];
xpos = cvt.ipos;
cvt.cpos[0] = opdata[4];
cvt.cpos[1] = opdata[5];
ypos = cvt.ipos;
break;
case 0x83: /* char. string at curr. pos. */
MoveTo(sx(xpos), sy(ypos)-2);
myDrawString(opdata+1);
break;
case 0xc3: /* char. string at given pos. */
cvt.cpos[0] = opdata[2];
cvt.cpos[1] = opdata[3];
xpos = cvt.ipos;
cvt.cpos[0] = opdata[4];
cvt.cpos[1] = opdata[5];
ypos = cvt.ipos;
MoveTo(sx(xpos), sy(ypos));
opdata[5] = opdata[1] - 4;
if (opdata[5] < 0) opdata[5] = 0;
myDrawString(opdata+5);
break;
case 0x85: /* fillet at current position */
/* see comment below for fillet at given position */
case 0x81: /* line at current position */
r = opdata[1]/4;
s = 2;
MoveTo(sx(xpos), sy(ypos));
while (r > 0) {
cvt.cpos[0] = opdata[s++];
cvt.cpos[1] = opdata[s++];
xpos = cvt.ipos;
cvt.cpos[0] = opdata[s++];
cvt.cpos[1] = opdata[s++];
ypos = cvt.ipos;
myLineTo(sx(xpos), sy(ypos));
r --;
}
break;
case 0xc5: /* fillet at given position */
/* Too hard to do correctly for now, but at least */
/* draw the lines the curve should be tangent to, */
/* and update the current position. Fillet has */
/* not been encountered in any test plots. */
case 0xc1: /* line at given position */
cvt.cpos[0] = opdata[2];
cvt.cpos[1] = opdata[3];
xpos = cvt.ipos;
cvt.cpos[0] = opdata[4];
cvt.cpos[1] = opdata[5];
ypos = cvt.ipos;
MoveTo(sx(xpos), sy(ypos));
r = (opdata[1]-4)/4;
s = 6;
while (r > 0) {
cvt.cpos[0] = opdata[s++];
cvt.cpos[1] = opdata[s++];
xpos = cvt.ipos;
cvt.cpos[0] = opdata[s++];
cvt.cpos[1] = opdata[s++];
ypos = cvt.ipos;
myLineTo(sx(xpos), sy(ypos));
r --;
}
break;
case 0xe1: /* relative line at given pos. */
cvt.cpos[0] = opdata[2];
cvt.cpos[1] = opdata[3];
xpos = cvt.ipos;
cvt.cpos[0] = opdata[4];
cvt.cpos[1] = opdata[5];
ypos = cvt.ipos;
MoveTo(sx(xpos), sy(ypos));
r = (opdata[1]-4)/2;
s = 6;
while (r > 0) {
xpos += (char)opdata[s++];
ypos += (char)opdata[s++];
myLineTo(sx(xpos), sy(ypos));
r --;
}
break;
case 0xc7: /* full arc at given position */
/* Arcs are not supported yet, but at least move to */
/* the specified position. Arc commands have not */
/* been encountered in any test plots. */
cvt.cpos[0] = opdata[2];
cvt.cpos[1] = opdata[3];
xpos = cvt.ipos;
cvt.cpos[0] = opdata[4];
cvt.cpos[1] = opdata[5];
ypos = cvt.ipos;
break;
case 0x87: /* full arc at current position */
/* doesn't affect current position */
case 0x22: /* set arc parameters */
break;
case 0x26: /* set extended color */
setrgb(&newcolor, opdata[3]);
if (colormac) {
GetEntryColor(myPalette, newcolor, &rgbtemp);
RGBForeColor(&rgbtemp); /* set foreground drawing color */
}
else {
if (newcolor == RGBblack) {
ForeColor(whiteColor);
}
else {
ForeColor(blackColor);
}
}
break;
case 0x0a: /* set color */
setrgb(&newcolor, opdata[1]);
if (colormac) {
GetEntryColor(myPalette, newcolor, &rgbtemp);
RGBForeColor(&rgbtemp); /* set foreground drawing color */
}
else {
if (newcolor == RGBblack) {
ForeColor(whiteColor);
}
else {
ForeColor(blackColor);
}
}
break;
case 0x68: /* begin area */
mypoly = OpenPoly(); /* create new polygon */
aflags = opdata[1]; /* save flag bits */
area_active = 1; /* remeber area is active */
break;
case 0x60: /* end area */
if (area_active == 0) { /* check for datastream error */
break;
}
ClosePoly(); /* done saving stuff */
PenPat(fillpat); /* set fill pattern */
PaintPoly(mypoly); /* draw it */
PenPat(qd.black); /* restore default pattern */
if (aflags & 0x40) FramePoly(mypoly); /* handle outline */
KillPoly(mypoly); /* dispose of it */
area_active = 0; /* reset active flag */
break;
case 0x28: /* set pattern symbol (area fill pattern) */
setpat(fillpat, opdata[1]);
break;
case 0x29: /* set marker symbol */
setmark(&markchar, opdata[1]);
break;
case 0xc2: /* marker at given position */
case 0x82: /* marker at current position */
r = opdata[1]/4;
s = 2;
while (r > 0) {
cvt.cpos[0] = opdata[s++];
cvt.cpos[1] = opdata[s++];
xpos = cvt.ipos;
cvt.cpos[0] = opdata[s++];
cvt.cpos[1] = opdata[s++];
ypos = cvt.ipos;
MoveTo(sx(xpos), sy(ypos)+4);
markstr[1] = markchar; /* make 1-character Pascal string */
myDrawString(markstr);
r --;
}
break;
case 0x18: /* set line type */
if (opdata[1] == 0) linet = dfltlt;
else linet = opdata[1];
break;
case 0x19: /* set line width */
if (opdata[1] == 0) linew = dfltlw;
else linew = opdata[1];
break;
case 0xd1: /* begin image */
case 0x91: /* begin image at current position */
image_srcRect.top = 0;
image_srcRect.left = 0;
image_srcRect.bottom = 1;
if (opdata[0] == 0xd1) {
/* ignore if not in the format we expect*/
if (opdata[1] != 10) break;
if (opdata[6] != 0) break;
if (opdata[7] != 0) break;
/* define upper left corner of bitmap */
cvt.cpos[0] = opdata[2];
cvt.cpos[1] = opdata[3];
image_dstRect.left = sx(cvt.ipos);
cvt.cpos[0] = opdata[4];
cvt.cpos[1] = opdata[5];
image_dstRect.top = sy(cvt.ipos);
imgoffset = 8;
}
else {
/* ignore if not in the format we expect*/
if (opdata[1] != 6) break;
if (opdata[2] != 0) break;
if (opdata[3] != 0) break;
/* define upper left corner of bitmap */
image_dstRect.left = sx(xpos);
image_dstRect.top = sy(ypos);
imgoffset = 4;
}
image_dstRect.bottom = image_dstRect.top + 1;
/* convert width */
cvt.cpos[0] = opdata[imgoffset];
cvt.cpos[1] = opdata[imgoffset+1];
image_srcRect.right = cvt.ipos;
image_dstRect.right = image_dstRect.left + cvt.ipos;
image_srcBits.rowBytes = (cvt.ipos+7)/8;
if (image_srcBits.rowBytes%2) image_srcBits.rowBytes++;
/* convert height */
cvt.cpos[0] = opdata[imgoffset+2];
cvt.cpos[1] = opdata[imgoffset+3];
image_rowcount = cvt.ipos;
image_srcBits.bounds = image_srcRect;
if (pictopen) {
if (image_dstRect.top < ymin) ymin = image_dstRect.top;
if (image_dstRect.top > ymax) ymax = image_dstRect.top;
if (image_dstRect.bottom < ymin) ymin = image_dstRect.bottom;
if (image_dstRect.bottom > ymax) ymax = image_dstRect.bottom;
if (image_dstRect.left < xmin) xmin = image_dstRect.left;
if (image_dstRect.left > xmax) xmax = image_dstRect.left;
if (image_dstRect.right < xmin) xmin = image_dstRect.right;
if (image_dstRect.right > xmax) xmax = image_dstRect.right;
}
image_active = 1;
break;
case 0x92: /* image data */
if (image_active == 0) break;
if (image_rowcount == 0) break;
image_rowcount--;
imageptr = imagebuff;
if (((long)imageptr)%2) imageptr++;
memcpy(imageptr, opdata+2, opdata[1]);
image_srcBits.baseAddr = imageptr;
if (colormac) {
GetBackColor(&rgbtemp);
if (cs.invertbw) {
RGBBackColor(&realwhite);
}
else {
RGBBackColor(&realblack);
}
CopyBits(&image_srcBits, &(dp->portBits),
&image_srcRect, &image_dstRect, copymode, 0L);
RGBBackColor(&rgbtemp);
}
else {
CopyBits(&image_srcBits, &(dp->portBits),
&image_srcRect, &image_dstRect, copymode, 0L);
}
image_dstRect.top++;
image_dstRect.bottom++;
break;
case 0x93: /* end image */
if (image_active == 0) break;
image_active = 0;
break;
case 0x0c: /* set foreground mix */
setmixmode(opdata[1]);
break;
/* The following are not easily implemented using QuickDraw; */
/* none of these appear to be needed for the test plots to */
/* display correctly: */
case 0x33: /* set character cell */
case 0x34: /* set character angle */
case 0x35: /* set character shear */
case 0x38: /* set character set */
case 0x3a: /* set character direction */
case 0x37: /* set marker cell */
case 0xff: /* end of symbol definition */
/* The following are documented by IBM to be ignored in files */
/* imported into GGXA, and are unlikely to be used. None of */
/* of the test plots need them. */
case 0x0d: /* set background mix */
/* no-op for 3179 */
case 0x39: /* set character precision */
case 0x3b: /* set marker precision */
case 0x3c: /* set marker set */
case 0x08: /* set pattern set */
case 0x43: /* set pick identifier */
case 0x04: /* segment characteristics */
case 0x3e: /* end prologue */
case 0x71: /* end segment */
/* these do nothing by definition */
case 0x01: /* comment */
case 0x00: /* no-op */
break;
default:
if (cs.dblevel == 3) break; /* for level 3, already dumped */
wsfdbg.grf_op = opdata[0]; /* temp */
hexdump(opdata, len); /* temp */
break;
}
if (PictPtr != 0) resetgdev();
SetPort(gp);
}
grcparse(c)
unsigned char c;
{
static short ctemp1, cboff, ccount;
static char cmode;
static unsigned char ctlbuff[257];
if (cleft == 0) {
cmode = ccount = 0;
cleft = 12;
}
switch (cmode) {
case 0: /* processing procedure header */
if (ccount == 8) ctemp1 = c;
if (ccount == 9) cleft = (ctemp1 << 8) + c + 3;
if (ccount == 11) {
cmode = 1;
ccount = 0;
}
else ccount++;
break;
case 1: /* processing procedural instruction */
if (ccount == 0) {
cboff = 0;
ctlbuff[cboff++] = c;
if (c == 0x00) {
exctl(ctlbuff, cboff);
ccount = 0;
}
else ccount++;
break;
}
ctlbuff[cboff++] = c;
if (ccount == 1) {
if ((ctlbuff[0] >= 0x08) && (ctlbuff[0] <= 0x0f)) {
exctl(ctlbuff, cboff);
ccount = 0;
}
else {
ctemp1 = c; /* no. of operand bytes left */
ccount++;
}
break;
}
ccount++;
ctemp1--;
if (ctemp1 == 0) {
exctl(ctlbuff, cboff);
ccount = 0;
}
break;
default:
break;
}
cleft--;
}
exctl(opdata, len) /* process control command */
unsigned char * opdata;
short len;
{
GrafPtr gp;
char setdflt;
short i;
GetPort(&gp);
if (PictPtr != 0) {
SetPort(PictPtr);
setgdev();
}
else SetPort(myWindow);
if (cs.dblevel == 3) { /* for level 3, dump all graphics */
wsfdbg.grf_op = opdata[0]; /* temp */
hexdump(opdata, len); /* temp */
}
switch(opdata[0]) {
case 0x0a: /* erase graphics space */
clrpict();
break;
case 0x00: /* no operation */
case 0x01: /* comment */
case 0x0f: /* stop draw */ /* no-op for 3179 */
break;
case 0x21: /* set current defaults */
/* untested- not used by test plots */
setdflt = (opdata[5] & 0x80) == 0;
switch(opdata[2]) { /* SET code */
case 0x00: /* drawing attributes */
i = 6; /* offset for next data byte */
if (opdata[3] & 0x80) { /* color specified */
if (setdflt) dfltcolor = 4; /* green */
else dfltcolor = opdata[i+1];
i += 2;
}
if (opdata[3] & 0x20) { /* foreground mix specified */
if (setdflt) dfltmix = 2; /* overpaint */
else dfltmix = opdata[i];
i++;
}
break;
case 0x01: /* line attributes */
i = 6; /* offset for next data byte */
if (opdata[3] & 0x80) { /* line type specified */
if (setdflt) dfltlt = 7; /* default is solid line */
else dfltlt = opdata[i];
i++;
}
if (opdata[3] & 0x40) /* line width specified */
if (setdflt) dfltlw = 1; /* default is 1 pixel wide */
else dfltlw = opdata[i];
break;
case 0x02: /* character attributes */
break; /* not supported */
case 0x03: /* marker attributes */
i = 6; /* offset for next data byte */
if (opdata[3] & 0x40) /* cellsize */
i += 4;
if (opdata[3] & 0x10) /* precision */
i += 1;
if (opdata[3] & 0x08) /* symbol set */
i += 1;
if (opdata[3] & 0x01) /* marker symbol */
if (setdflt) dfltmarker = 0xb5; /* diamond */
else setmark(&dfltmarker, opdata[i]);
break;
case 0x04: /* pattern attributes */
i = 6; /* offset for next data byte */
if (opdata[3] & 0x08) /* symbol set */
i += 1;
if (opdata[3] & 0x01) /* pattern symbol */
if (setdflt) setpat(dfltpat, 16);
else setpat(dfltpat, opdata[i]);
break;
case 0x0b: /* arc parameters */
break; /* not supported */
default: /* reserved; SAS & GDDM use 0x05, 0x07 */
if (cs.dblevel == 3) break; /* for level 3, dumped already */
wsfdbg.grf_op = opdata[0]; /* temp */
hexdump(opdata, len); /* temp */
break;
}
break;
/* no support for the graphics cursor */
case 0x08: /* attach graphic cursor */
case 0x09: /* detach graphic cursor */
case 0x31: /* set graphic cursor pos. */
break;
default:
if (cs.dblevel == 3) break; /* for level 3, dumped already */
wsfdbg.grf_op = opdata[0]; /* temp */
hexdump(opdata, len); /* temp */
break;
}
if (PictPtr != 0) resetgdev();
SetPort(gp);
}
clrpict() /* erase graphics space */
{
GrafPtr gp;
RGBColor rgbtemp;
static unsigned char endarea[] = {0x60, 0};
static unsigned char endimage[] = {0x93, 0};
pndclr = 0; /* reset pending clear */
if (drawpict == 0) return; /* nothing to do if no graphics */
if (area_active) { /* end area if still active */
exdraw(endarea, 2); /* execute end area command */
}
if (image_active) { /* end image if still active */
exdraw(endimage, 2); /* execute end image command */
}
if (pictopen) { /* close PICT file if open */
closepictfile();
}
GetPort(&gp); /* save current GrafPort */
if (PictPtr == 0) { /* erase port we draw in */
SetPort(myWindow);
EraseRect(&(myWindow->portRect));
setmixmode(0); /* set default pen mode */
}
else {
SetPort(PictPtr);
setgdev();
EraseRect(&(PictPort.portRect));
setmixmode(0);
resetgdev();
}
if (colormac) {
SetPort(WritePtr); /* restore background color */
if (textmap) setgdev();
GetEntryColor(myPalette, RGBback, &rgbtemp);
RGBBackColor(&rgbtemp);
if (textmap) resetgdev();
}
SetPort(gp); /* restore GrafPort */
drawpict = 0; /* don't show graphics any more */
newpict = 1; /* next order starts new picture */
if (pendalign) { /* align bitmaps if changed during display */
alignbitmaps();
newstat();
}
invldscr(); /* force screen to be redrawn */
/* end saving PICT file */
}
initpict() /* initialize at start of new picture */
{
if (!newpict) return;
drawpict = 1; /* clear initial screen */
clrpict(); /* (resets drawpict, sets newpict) */
newpict = 0; /* no longer new picture */
/* begin saving PICT file */
if (savepict && (PictPtr != 0)) {
openpictfile();
}
}
showpict() /* cause graphics data to be displayed */
{
GrafPtr gp;
RGBColor rgbtemp;
drawpict = 1; /* include graphics in screen updates */
if (colormac) { /* change text background to black or white */
GetPort(&gp);
SetPort(WritePtr);
if (textmap) setgdev();
if (cs.invertbw) GetEntryColor(myPalette, RGBwhite, &rgbtemp);
else GetEntryColor(myPalette, RGBblack, &rgbtemp);
RGBBackColor(&rgbtemp);
SetPort(gp);
if (textmap) resetgdev();
}
invldscr(); /* invalidate screen to force update */
}
/* The following two function are simple now, since Mac3270's response to
WSF Query Reply now accurately describes the Mac screen dimensions.
Both SAS and GDDM adapt to this very well. */
sx(x) /* convert data stream x-coordinate to Mac coordinate */
short x;
{
register short r;
/* if (PictPtr == 0) {
if (cur_ptsize == 12) r = x + 286;
else r = x + 246;
}
else {
if (cur_ptsize == 12) r = x + 318;
else r = x + 255;
} */
r = x + hpixsize/2;
if (PictPtr == 0) {
r += textRect.left;
}
if (pictopen) {
if (r < xmin) xmin = r;
if (r > xmax) xmax = r;
}
return(r);
}
sy(y) /* convert data stream y-coordinate to Mac coordinate */
short y;
{
register short r;
/* if (PictPtr == 0) {
if ((cur_ptsize == 9) && (cur_rows == 24)) r = 139 - y;
else r = 188 - y;
}
else {
if ((cur_ptsize == 9) && (cur_rows == 24)) r = 146 - y;
else r = 195 - y;
} */
r = (vpixsize - 19)/2 - y;
if (PictPtr == 0) {
r += textRect.top;
}
if (pictopen) {
if (r < ymin) ymin = r;
if (r > ymax) ymax = r;
}
return(r);
}
myLineTo(x, y)
short x, y;
{
switch (linet) { /* set pen pattern for line type */
case 8: /* invisible */
PenPat(qd.white);
break;
default: /* all other, until I figure out how to do this */
PenPat(qd.black);
break;
}
/* set pen width as requested */
if (linew == 0) PenSize(1, 1);
else PenSize(linew, linew);
LineTo(x, y); /* draw the line */
PenPat(qd.black); /* restore QuickDraw defaults */
PenSize(1, 1);
}
myDrawString(s)
unsigned char *s; /* s is a Pascal string */
{
short i;
unsigned char xlstr[256]; /* translated copy of string */
Point penloc;
short texttop, textleft, textbottom, textright;
FontInfo fi;
if (s[0] == 0) return; /* just return if null string */
xlstr[0] = s[0]; /* copy the string */
movmem(s+1, xlstr+1, s[0]);
if (nl_handle != 0) {
for (i=1; i <= xlstr[0]; i++) /* translate EBCDIC for language */
xlstr[i] = nltab[xlstr[i]];
}
if (pictopen && (xtabh != 0)) {
for (i=1; i <= xlstr[0]; i++) /* translate string to ASCII */
xlstr[i] = (*xtabh)[xlstr[i]];
}
ptoc(xlstr);
if (pictopen) {
GetPen(&penloc);
textleft = penloc.h;
GetFontInfo(&fi);
texttop = penloc.v + fi.ascent;
textbottom = penloc.v - fi.descent - fi.leading;
}
DrawString(xlstr);
if (pictopen) {
GetPen(&penloc);
textright = penloc.h;
if (texttop > ymax) ymax = texttop;
if (texttop < ymin) ymin = texttop;
if (textbottom > ymax) ymax = textbottom;
if (textbottom < ymin) ymin = textbottom;
if (textleft < xmin) xmin = textleft;
if (textleft > xmax) xmax = textleft;
if (textright < xmin) xmin = textright;
if (textright > xmax) xmax = textright;
}
}
setrgb(newcolor, code) /* set newcolor from data stream code */
short * newcolor;
unsigned char code;
{
if ((code == 0) || (code == 16)) code = dfltcolor;
switch(code) {
case 1: /* blue */
case 9: /* dark blue */
(*newcolor) = RGBblue;
break;
case 2: /* red */
case 10: /* orange */
(*newcolor) = RGBred;
break;
case 3: /* pink */
case 11: /* purple */
(*newcolor) = RGBpink;
break;
case 4: /* green */
case 12: /* dark green */
(*newcolor) = RGBgreen;
break;
case 5: /* turquoise */
case 13: /* dark turquoise */
(*newcolor) = RGBturquoise;
break;
case 6: /* yellow */
case 14: /* mustard */
(*newcolor) = RGByellow;
break;
case 7: /* neutral */
case 15: /* gray */
if (cs.invertbw) (*newcolor) = RGBblack;
else (*newcolor) = RGBwhite;
break;
case 8: /* background */
if (cs.invertbw) (*newcolor) = RGBwhite;
else (*newcolor) = RGBblack;
break;
default:
if (cs.invertbw) (*newcolor) = RGBblack;
else (*newcolor) = RGBwhite;
break;
}
}
setmark(mark, code) /* convert marker code to character */
unsigned char * mark, code;
{
unsigned char markchar;
switch(code) {
case 0x00: /* default */
markchar = dfltmarker;
break;
case 0x01: /* cross */
markchar = 0x46; /* sort of a cross */
break;
case 0x02: /* plus */
markchar = 0x4e; /* normal plus */
break;
case 0x05: /* 6-point star */
case 0x06: /* 8-point star */
markchar = 0x5c; /* normal asterisk */
break;
default:
markchar = 0xb5; /* solid diamond */
break;
}
(*mark) = markchar; /* return result */
}
setpat(pat, code) /* define pattern from code */
unsigned char * pat, code;
{
static Pattern pattab[16] = {
{0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff}, /* 87.5% gray */
{0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77}, /* 75% gray */
{0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55}, /* 50% gray */
{0xaa, 0x00, 0x55, 0x00, 0xaa, 0x00, 0x55, 0x00}, /* 25% gray */
{0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00}, /* 12.5% gray */
{0x80, 0x00, 0x08, 0x00, 0x80, 0x00, 0x08, 0x00}, /* 6.25% gray */
{0x80, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00}, /* 3.125% gray */
{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 1.5625% gray */
{0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88}, /* vertical lines */
{0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00}, /* horizontal lines */
{0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88}, /* "/" diags, less steep */
{0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88}, /* "/" diags., 45 degrees */
{0x88, 0x88, 0x44, 0x44, 0x22, 0x22, 0x11, 0x11}, /* "\" diags., less steep */
{0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11}, /* "\" diags., 45 degrees */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* white (none) */
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; /* black (solid) */
if (code == 0) movmem(dfltpat, pat, 8);
else {
if (code > 16) code = 16;
movmem(pattab[code-1], pat, 8);
}
}
setmixmode(mode)
short mode;
{
if (mode == 0) mode = dfltmix;
switch(mode) {
case 1: /* "mix" colors */
if (colormac) {
if (cs.invertbw) {
PenMode(adMin);
copymode = adMin;
}
else {
PenMode(adMax);
copymode = adMax;
}
}
else {
PenMode(patOr);
copymode = srcOr;
}
break;
default: /* overpaint */
PenMode(patCopy);
copymode = srcCopy;
break;
}
}
openpictfile()
{
Point where;
ProcPtr dlgHook;
SFReply reply;
OSErr rc;
short i;
long longzero = 0;
long iocount;
GrafPtr gp;
where = sfppoint;
dlgHook = 0;
arrowcursor();
SFPutFile(&where, "Save graphics in:",
pict_fName, dlgHook, &reply);
if (reply.good == 0) return;
ptoc(&reply.fName);
movmem(&reply.fName, pict_fName, 64); /* save filename */
rc = FSDelete(&reply.fName, reply.vRefNum); /* delete existing file */
if ((rc != 0) && (rc != -43)) { /* file not found is ok */
stoperr(wpictalrt);
return;
}
rc = Create(&reply.fName, reply.vRefNum, 'MDRW', 'PICT');
if (rc != 0) {
stoperr(wpictalrt);
return;
}
rc = FSOpen(&reply.fName, reply.vRefNum, &pictfref);
if (rc != 0) {
stoperr(wpictalrt);
return;
}
/* write 512-byte header */
for (i=0; i < 512/4; i++) {
iocount = 4;
rc = FSWrite(pictfref, &iocount, &longzero);
if (rc != 0) break;
}
/* write fixed fields of PICT */
if (rc == 0) {
for (i=0; i < (sizeof(short) + sizeof(Rect))/2; i++) {
iocount = 2;
rc = FSWrite(pictfref, &iocount, &longzero);
if (rc != 0) break;
}
}
if (rc != 0) { /* clean up if write error */
FSClose(pictfref);
FSDelete(&reply.fName, reply.vRefNum);
stoperr(wpictalrt);
return;
}
pictvref = reply.vRefNum;
pictopen = 1;
picterr = 0;
xmin = ymin = 0x7fff;
xmax = ymax = 0x8000;
if (colormac) SetStdCProcs(&myProcs);
else SetStdProcs(&myProcs);
PictPtr->grafProcs = &myProcs;
myProcs.putPicProc = myStdPutPic;
GetPort(&gp);
SetPort(PictPtr);
TextFont(4);
picthandle = (Ptr)0L;
picthandle = OpenPicture(&PictPtr->portRect);
ShowPen();
PicComment(picDwgBeg, 0, 0L); /* start MacDraw Picture */
PicComment(picGrpBeg, 0, 0L); /* begin a group */
theWidth = NewHandle((Size)sizeof(Point));
if (theWidth != 0) {
((Point *)(*theWidth))->v = 1;
((Point *)(*theWidth))->h = 3; /* use 1/3 normal width */
PicComment(SetLineWidth, sizeof(Point), theWidth); /* set new line width */
}
pictcount = sizeof(Picture);
SetPort(gp);
}
closepictfile()
{
OSErr rc;
GrafPtr gp;
long iocount, pictpos;
struct pictfixed {
short pictlen;
Rect pictrect;
} pf;
GetPort(&gp);
SetPort(PictPtr);
PicComment(picGrpEnd, 0, 0L); /* end a group */
PicComment(picDwgEnd, 0, 0L); /* end MacDraw Picture */
HidePen();
ClosePicture();
TextFont(stdfont);
/* save the current file position */
if (picterr == 0) {
picterr = GetFPos(pictfref, &pictpos);
}
/* set position after MacDraw header */
if (picterr == 0) {
picterr = SetFPos(pictfref, fsFromStart, (long)512);
}
/* copy fixed picture fields */
movmem((Ptr)(*picthandle), &pf, sizeof(struct pictfixed));
/* adjust rectangle to match actual plot */
pf.pictrect.top = ymin;
pf.pictrect.left = xmin;
pf.pictrect.bottom = ymax;
pf.pictrect.right = xmax;
/* write the final fixed picture fields */
if (picterr == 0) {
iocount = sizeof(struct pictfixed);
picterr = FSWrite(pictfref, &iocount, &pf);
}
/* reset the file position to the end */
if (picterr == 0) {
picterr = SetFPos(pictfref, fsFromStart, pictpos);
}
KillPicture(picthandle);
SetPort(gp);
PictPtr->grafProcs = (Ptr)0L;
rc = FSClose(pictfref);
if (theWidth != 0) {
DisposHandle(theWidth);
}
pictopen = 0;
if ((rc != 0) || (picterr != 0)) {
stoperr(wpictalrt);
FSDelete(pict_fName, pictvref);
}
}
pascal void myStdPutPic(dataPtr, byteCount)
Ptr dataPtr;
unsigned short byteCount;
{
long iocount;
if (picterr != 0) return;
iocount = byteCount;
pictcount += byteCount;
picterr = FSWrite(pictfref, &iocount, dataPtr);
if (picthandle != 0) (*picthandle)->picSize = pictcount;
}
hexdump(data, len) /*temp*/
unsigned char * data;
short len;
{
short count, i;
FILE * fp;
static char openflg = 0;
if (!cs.dblevel) return;
if (openflg == 0) {
fp = fopen("Ram:wsfdebug", "w");
if (fp == 0) return;
openflg = 1;
}
else {
fp = fopen("Ram:wsfdebug", "a");
if (fp == 0) return;
}
fprintf(fp, "wsf_op = %x, wsf_gr = %x, grf_op = %x, length = %d\n",
wsfdbg.wsf_op, wsfdbg.wsf_gr, wsfdbg.grf_op, len);
count = 0;
for (i=0; i < len; i++) {
fprintf(fp, "%02x", data[i]);
count++;
if (count == 32) {
fprintf(fp, "\n");
count = 0;
}
}
if (count != 0) fprintf(fp, "\n");
fprintf(fp, "\n");
fclose(fp);
}